import axios from 'axios';
import {ElNotification, ElMessageBox} from 'element-plus';
import sysConfig from "@/config";
import tool from '@/utils/tool';
import router from '@/router';
import Config from "@/config"

axios.defaults.baseURL = ''

axios.defaults.timeout = sysConfig.TIMEOUT

/*是否有请求正在刷新token*/
window.isRefreshing = false;
// 挂起的请求数组
let refreshSubscribers = [];

/*push所有请求到数组中*/
function subscribeTokenRefresh(cb) {
	refreshSubscribers.push(cb)
}

/*刷新请求（refreshSubscribers数组中的请求得到新的token之后会自执行，用新的token去请求数据）*/
function onRefreshed(token) {
	refreshSubscribers.map(cb => cb(token))
}

// HTTP request 拦截器
axios.interceptors.request.use(
	config => {
		let accessToken = tool.data.get("TOKEN");
		if (accessToken && accessToken !== '') {
			config.headers[sysConfig.TOKEN_NAME] = sysConfig.TOKEN_PREFIX + accessToken;
		}

		// 判断是否需要更新token
		let refresh_token = tool.data.get('refresh_token')
		if (accessToken && refresh_token === 1 && config.url.indexOf('/token/refreshToken') === -1) {
			if (!window.isRefreshing) {
				/*将刷新token的标志置为true*/
				window.isRefreshing = true

				config.headers[sysConfig.TOKEN_NAME] = sysConfig.TOKEN_PREFIX + accessToken;
				if (!sysConfig.REQUEST_CACHE && config.method === 'get') {
					config.params = config.params || {};
					config.params['_'] = new Date().getTime();
				}
				Object.assign(config.headers, sysConfig.HEADERS);

				/*发起刷新token的请求*/
				http.post(`${Config.API_URL}/token/refreshToken`).then(res => {
					tool.data.set('refresh_token', 0);
					/*将标志置为false*/
					window.isRefreshing = false;
					/*更新token*/
					tool.data.set("TOKEN", res.data);

					/*执行数组里的函数,重新发起被挂起的请求*/
					onRefreshed(res.result)
					/*执行onRefreshed函数后清空数组中保存的请求*/
					refreshSubscribers = []
				}).catch(err => {
					alert(err.response.data.message);
					/*清除本地保存的auth*/
					// localStorage.removeItem('auth')
					window.location.href = '/'
				})
			}
			let retry = new Promise((resolve, reject) => {
				/*(token) => {...}这个函数就是回调函数*/
				subscribeTokenRefresh((token) => {
					config.headers.common['Authorization'] = token;
					/*将请求挂起*/
					resolve(config)
				})
			})
			return retry
		}
		return config;
	},
	(error) => {
		return Promise.reject(error);
	}
);

// HTTP response 拦截器
axios.interceptors.response.use(
	(response) => {
		if (response.data.code === 401) {
			tool.data.set('refresh_token', 1);
		}
		if (response.data.code === 500) {
			ElNotification.error({
				title: '请求错误',
				message: response.data.errorMsg || "服务器发生错误！"
			});
		}
		if (response.data.code === 402) {
			ElMessageBox.confirm('当前用户已被登出或无权限访问当前资源，请尝试重新登录后再操作。', '无权限访问', {
				type: 'error',
				closeOnClickModal: false,
				center: true,
				confirmButtonText: '重新登录',
				cancelButtonText: '取消'
			}).then(() => {
				router.replace({path: '/login'});
			}).catch(() => {
			})
		}
		return response;
	},
	(error) => {
		if (error.response) {
			if (error.response.status == 404) {
				ElNotification.error({
					title: '请求错误',
					message: "Status:404，正在请求不存在的服务器记录！"
				});
			} else if (error.response.status == 500) {
				ElNotification.error({
					title: '请求错误',
					message: error.response.data.message || "Status:500，服务器发生错误！"
				});
			} else if (error.response.status == 401) {
				ElMessageBox.confirm('当前用户已被登出或无权限访问当前资源，请尝试重新登录后再操作。', '无权限访问', {
					type: 'error',
					closeOnClickModal: false,
					center: true,
					confirmButtonText: '重新登录'
				}).then(() => {
					router.replace({path: '/login'});
				}).catch(() => {
				})
			} else {
				ElNotification.error({
					title: '请求错误',
					message: error.response.data.message || `Status:${error.response.status}，未知错误！`
				});
			}
		} else {
			ElNotification.error({
				title: '请求错误',
				message: "请求服务器无响应！"
			});
		}

		return Promise.reject(error.response);
	}
);

var http = {

	/** get 请求
	 * @param  {接口地址} url
	 * @param  {请求参数} params
	 * @param  {参数} config
	 */
	get: function (url, params = {}, config = {}) {
		return new Promise((resolve, reject) => {
			axios({
				method: 'get',
				url: url,
				params: params,
				...config
			}).then((response) => {
				resolve(response.data);
			}).catch((error) => {
				reject(error);
			})
		})
	},

	/** post 请求
	 * @param  {string} url
	 * @param  {请求参数} data
	 * @param  {参数} config
	 */
	post: function (url, data = {}, config = {}) {
		return new Promise((resolve, reject) => {
			axios({
				method: 'post',
				url: url,
				data: data,
				...config
			}).then((response) => {
				resolve(response.data);
			}).catch((error) => {
				reject(error);
			})
		})
	},

	/** put 请求
	 * @param  {接口地址} url
	 * @param  {请求参数} data
	 * @param  {参数} config
	 */
	put: function (url, data = {}, config = {}) {
		return new Promise((resolve, reject) => {
			axios({
				method: 'put',
				url: url,
				data: data,
				...config
			}).then((response) => {
				resolve(response.data);
			}).catch((error) => {
				reject(error);
			})
		})
	},

	/** patch 请求
	 * @param  {接口地址} url
	 * @param  {请求参数} data
	 * @param  {参数} config
	 */
	patch: function (url, data = {}, config = {}) {
		return new Promise((resolve, reject) => {
			axios({
				method: 'patch',
				url: url,
				data: data,
				...config
			}).then((response) => {
				resolve(response.data);
			}).catch((error) => {
				reject(error);
			})
		})
	},

	/** delete 请求
	 * @param  {接口地址} url
	 * @param  {请求参数} data
	 * @param  {参数} config
	 */
	delete: function (url, data = {}, config = {}) {
		return new Promise((resolve, reject) => {
			axios({
				method: 'delete',
				url: url,
				data: data,
				...config
			}).then((response) => {
				resolve(response.data);
			}).catch((error) => {
				reject(error);
			})
		})
	},

	/** jsonp 请求
	 * @param  {接口地址} url
	 * @param  {JSONP回调函数名称} name
	 */
	jsonp: function (url, name = 'jsonp') {
		return new Promise((resolve) => {
			var script = document.createElement('script')
			var _id = `jsonp${Math.ceil(Math.random() * 1000000)}`
			script.id = _id
			script.type = 'text/javascript'
			script.src = url
			window[name] = (response) => {
				resolve(response)
				document.getElementsByTagName('head')[0].removeChild(script)
				try {
					delete window[name];
				} catch (e) {
					window[name] = undefined;
				}
			}
			document.getElementsByTagName('head')[0].appendChild(script)
		})
	}
}

export default http;
